{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 面向对象\n",
    "\n",
    "欢迎大家回到 Machine Learning Diary~👏\n",
    "\n",
    "今天这节课终于到了面向对象编程这一步。Python使用类(class)和对象(object)，进行面向对象（object-oriented programming，简称OOP）的编程。之前教程里出现的一步步编程大多为面向过程编程。\n",
    "\n",
    "面向对象编程这个技能就是当你代码越敲越多，就越来越明白面向对象的好。因为它的一大特点就是提高代码的复用性。我觉得所有的技能都是水到渠成的，对于入门者可能写不习惯，但是没关系，可以先了解下，稍微有个印象。\n",
    "\n",
    "我们先来弄清楚面向对象编程最重要的两个概念：类(class)对象(object），对象也经常叫实例(Instance)。我们接下来就叫实例。\n",
    "\n",
    "\n",
    "## 创建类\n",
    "\n",
    "物以类聚，人以群分。我们先来尝试创建一个类，以 博主Blogger 类为例，在python中，定义类通过```class```："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Blogger(object):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 创建实例\n",
    "\n",
    "好了，现在我们已经创建了一个最简单的Blogger类，里面什么也没有。但是，当我们来实例化一个对象看看："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<__main__.Blogger object at 0x0000021955A7E470>\n",
      "<class '__main__.Blogger'>\n"
     ]
    }
   ],
   "source": [
    "CodeWithZhangYi = Blogger()  # 创建实例：CodeWithZhangYi\n",
    "print(CodeWithZhangYi)       # 打印实例\n",
    "print(Blogger)               # 打印类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "变量CodeWithZhangYi指向的就是一个Blogger的实例，后面的0x0000021955A7E470是内存地址，每个object的地址都不一样，而Blogger本身则是一个类。\n",
    "\n",
    "## 创建属性\n",
    "\n",
    "现在为Blogger这个类里面增加一些属性(Attributes)。比如博主的名字name，关注者followers，类别category等等。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ZhangYi\n"
     ]
    }
   ],
   "source": [
    "CodeWithZhangYi.name = 'ZhangYi'\n",
    "print(CodeWithZhangYi.name)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "好了，现在来正儿八经地写一个有各种属性的Blogger类："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Blogger(object):\n",
    "    def __init__(self, name, gender):\n",
    "        print('start initialization...')\n",
    "        self.name = name\n",
    "        self.gender = gender\n",
    "        \n",
    "    \n",
    "    def say_hello(self):\n",
    "        print('Hello, this is',self.name)\n",
    "    \n",
    "    def followers(self, follower_num):\n",
    "        if follower_num > 5000:\n",
    "            print('此博主值得关注一下')\n",
    "        else:\n",
    "            print('此博主值得观望一下')\n",
    "    \n",
    "    def category(self, category):\n",
    "        if category == 'coder':\n",
    "            if self.gender == 'female':\n",
    "                print('她是程序媛博主')\n",
    "            else:\n",
    "                print('他是程序猿博主')\n",
    "        else:\n",
    "            print('他/她是非编程类博主')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "首先来介绍下上面这个自定义的Blogger类。新建类时，```class```后面紧接着是类名，即Blogger，类名通常是大写开头的单词，紧接着是(object)，表示该类是从哪个类继承下来的，继承的概念我们后面再讲，通常，如果没有合适的继承类，就使用object类，这是所有类最终都会继承的类。\n",
    "\n",
    "由于类可以起到模板的作用，因此，可以在创建实例的时候，把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的\\_\\_init\\_\\_方法（注意！\\_\\_init\\_\\_这里左右都有两个下划线！！），在创建实例的时候，就把name，gender等属性绑上去：\n",
    "\n",
    "紧接着，我又自定义了三个属性，分别是：\n",
    "- say_hello\n",
    "- 根据follower数量输出此博主值不值得被关注（当然这是我随便写的规则，勿喷）\n",
    "- 根据博主类别和性别判断是否为编程博主，以及是的话编程博主的程序员属性（同样随便编的规则，勿喷）\n",
    "\n",
    "这里每个属性都是由函数定义的，之前教过定义函数的开头就是```def``` ，是不是很熟悉~有些函数需要传入参数，比如```followers``` 和```category``` ，有些不需要传入参数，比如```say_hello``` 。这里每个def括号里的```self```都是class属性自带的一个参数。暂时就把这个当作规则记住。后面再详细解释。\n",
    "\n",
    "定义好了Blogger类，就可以根据Blogger类创建出Blogger的实例，创建实例是通过类名+()实现的，这里我定义的Blogger需要传入参数(name, gender)，因此我们来创建一个名叫Girls-In-AI的博主实例："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "start initialization...\n"
     ]
    }
   ],
   "source": [
    "GIA = Blogger('Girls-In-AI','female')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上面这句就是在实例化Blogger这个类。GIA变量就是实例结果。根据传入的参数，我们知道GIA是一个名字叫'Girls-In-AI'的女博主。\n",
    "\n",
    "接下来尝试下各种属性，先来打个招呼："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello, this is Girls-In-AI\n"
     ]
    }
   ],
   "source": [
    "GIA.say_hello()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "再根据这个脑残规则看看GIA这个博主值不值得你马上follow一下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "此博主值得观望一下\n"
     ]
    }
   ],
   "source": [
    "GIA.followers(3788)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "sad...被自己定义的傻规则伤到😭 我们再来根据博主类别看看博主新属性："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "她是程序媛博主\n"
     ]
    }
   ],
   "source": [
    "GIA.category('coder')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "假如GIA是个阅读博主，再来看看博主属性输出是什么："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "他/她是非编程类博主\n"
     ]
    }
   ],
   "source": [
    "GIA.category('reader')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "好了，到现在为止，是不是对于面向对象编程稍微有点感觉了~\n",
    "\n",
    "本文算是对于面向对象编程学习的抛砖引玉，因为面向对象编程的玩法实在太多了。更多更有技巧的可以在日后的编程学习中再了解。比如：\n",
    "\n",
    "面向对象编程的三大特色是：\n",
    "- 封装\n",
    "- 继承\n",
    "- 多态\n",
    "\n",
    "👩好啦，今天的课程就到这里啦！咱们下次见！~"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
